#include "camera_driver.h"
#include "time_sntp_driver.h"

static const char *TAG = "camera_driver";

static QueueHandle_t xQueueLCDFrame = NULL;
TaskHandle_t xHandleTaskCameraGet = NULL;
camera_fb_t *frame = NULL;
camera_config_t *camera_config;
TaskHandle_t task_camera_get_handle, task_camera_show_handle, task_take_photo_handle;

bool camera_tasks_enabled = true;
bool take_photo_enabled = true;

extern int32_t select_pixel;

void task_camera_show(void *arg)
{
    // 创建LVGL图像对象
    lv_obj_t *img = lv_img_create(objects.home);
    lv_obj_set_align(img, LV_ALIGN_CENTER);
    lv_obj_move_background(img);

    // 创建LVGL图像描述符
    static lv_img_dsc_t img_dsc = {
        .header.always_zero = 0,
        .header.w = 320,
        .header.h = 240,
        .header.cf = LV_IMG_CF_TRUE_COLOR,
        .data_size = 320 * 240 * 2,
        .data = NULL};

    switch (select_pixel)
    {
    case 0:
        img_dsc.header.w = 320;
        img_dsc.header.h = 240;
        img_dsc.data_size = 320 * 240 * 2;
        break;
    case 1:
        img_dsc.header.w = 160;
        img_dsc.header.h = 120;
        img_dsc.data_size = 160 * 120 * 2;
        break;
    case 2:
        img_dsc.header.w = 640;
        img_dsc.header.h = 480;
        img_dsc.data_size = 640 * 480 * 2;
        break;
    }

    while (true)
    {
        if (xQueueReceive(xQueueLCDFrame, &frame, portMAX_DELAY))
        {
            img_dsc.data = (void *)frame->buf;

            if (lvgl_port_lock(0))
            {
                switch (select_pixel)
                {
                case 0:
                    lv_img_set_src(img, &img_dsc);
                    break;
                case 1:
                    lv_img_set_src(img, &img_dsc);
                    lv_img_set_zoom(img, 512);
                    break;
                case 2:
                    lv_img_set_src(img, &img_dsc);
                    lv_img_set_zoom(img, 128);
                    break;
                }
                lvgl_port_unlock();
                vTaskDelay(pdMS_TO_TICKS(15));
            }

            esp_camera_fb_return(frame);
        }
    }
}

// 摄像头处理任务
void task_camera_get(void *arg)
{
    while (true)
    {
        if (camera_tasks_enabled)
        {
            frame = esp_camera_fb_get();
            if (frame)
            {
                xQueueSend(xQueueLCDFrame, &frame, portMAX_DELAY);
                // ESP_LOGI(TAG, "get frame");
            }
            vTaskDelay(pdMS_TO_TICKS(20));
        }
        else
        {
            vTaskDelay(pdMS_TO_TICKS(20));
        }
    }
}

void task_take_photo(void *arg)
{
    char filename[32];
    char time_str[32];

    while (true)
    {
        ESP_LOGI(TAG, "check button");
        if (button_wait_press(portMAX_DELAY) && take_photo_enabled)
        {
            ESP_LOGI(TAG, "button pressed");
            camera_tasks_enabled = false;

            if (lvgl_port_lock(0))
            {
                lv_obj_clear_flag(objects.spinner, LV_OBJ_FLAG_HIDDEN);
                lvgl_port_unlock();
            }

            camera_fb_t *photo_frame = esp_camera_fb_get();

            if (photo_frame)
            {
                ESP_LOGI(TAG, "get photo frame");

                snprintf(filename, sizeof(filename), "/sdcard/testImg.bin", time_str);
                FILE *file_bef = fopen(filename, "wb");
                if (file_bef)
                {
                    fwrite(photo_frame->buf, 1, photo_frame->len, file_bef);
                    fclose(file_bef);
                    ESP_LOGI(TAG, "Saved %s", filename);
                    printf("前16字节: ");
                    for (int i = 0; i < 16; i++)
                        printf("%02X ", photo_frame->buf[i]);
                    printf("\n");
                }
                else
                {
                    ESP_LOGE(TAG, "Failed to open file %s", filename);
                }

                static uint8_t *jpeg_buf = NULL;
                static size_t jpeg_buf_len = 0;
                if (fmt2jpg(photo_frame->buf, photo_frame->len, photo_frame->width, photo_frame->height,
                            PIXFORMAT_RGB565, 100, &jpeg_buf, &jpeg_buf_len) == true)
                {
                    ESP_LOGI(TAG, "fmt size:%d,jpg size:%d", photo_frame->len, jpeg_buf_len);
                    get_time_file_name_format(time_str);
                    snprintf(filename, sizeof(filename), "/sdcard/%s.jpg", time_str);

                    FILE *file = fopen(filename, "wb");
                    if (file)
                    {
                        fwrite(jpeg_buf, 1, jpeg_buf_len, file);
                        fclose(file);
                        ESP_LOGI(TAG, "Saved %s", filename);
                    }
                    else
                    {
                        ESP_LOGE(TAG, "Failed to open file %s", filename);
                    }
                    // 释放JPEG缓存
                    free(jpeg_buf);
                    if (file)
                    {
                        fflush(file);
                    }
                }
                esp_camera_fb_return(photo_frame);
            }

            save_time_into_file();

            if (lvgl_port_lock(0))
            {
                lv_obj_add_flag(objects.spinner, LV_OBJ_FLAG_HIDDEN);
                lvgl_port_unlock();
            }
            camera_tasks_enabled = true;
        }
        else
        {
            vTaskDelay(pdMS_TO_TICKS(20));
        }
    }
}

void camera_init(int jpeg_quality_set, framesize_t frame_size_set)
{
    xQueueLCDFrame = xQueueCreate(3, sizeof(camera_fb_t *));

    dvp_pwdn(0); // 打开摄像头
    camera_config_t config;
    config.ledc_channel = LEDC_CHANNEL_1; // LEDC通道选择  用于生成XCLK时钟 但是S3不用
    config.ledc_timer = LEDC_TIMER_1;     // LEDC timer选择  用于生成XCLK时钟 但是S3不用
    config.pin_d0 = CAMERA_PIN_D0;
    config.pin_d1 = CAMERA_PIN_D1;
    config.pin_d2 = CAMERA_PIN_D2;
    config.pin_d3 = CAMERA_PIN_D3;
    config.pin_d4 = CAMERA_PIN_D4;
    config.pin_d5 = CAMERA_PIN_D5;
    config.pin_d6 = CAMERA_PIN_D6;
    config.pin_d7 = CAMERA_PIN_D7;
    config.pin_xclk = CAMERA_PIN_XCLK;
    config.pin_pclk = CAMERA_PIN_PCLK;
    config.pin_vsync = CAMERA_PIN_VSYNC;
    config.pin_href = CAMERA_PIN_HREF;
    config.pin_sccb_sda = -1; // 这里写-1 表示使用已经初始化的I2C接口
    config.pin_sccb_scl = CAMERA_PIN_SIOC;
    config.sccb_i2c_port = 0;
    config.pin_pwdn = CAMERA_PIN_PWDN;
    config.pin_reset = CAMERA_PIN_RESET;
    config.xclk_freq_hz = XCLK_FREQ_HZ;
    config.pixel_format = PIXFORMAT_RGB565;
    config.frame_size = FRAMESIZE_QVGA;
    config.jpeg_quality = 12;
    config.fb_count = 4; // 增加帧缓冲区数量
    config.fb_location = CAMERA_FB_IN_PSRAM;
    config.grab_mode = CAMERA_GRAB_LATEST; // 修改为获取最新帧

    ESP_LOGI(TAG, "Camera Init,jpeg_quality:%d,frame_size:%d", jpeg_quality_set, frame_size_set);

    // camera init
    esp_err_t err = esp_camera_init(&config); // 配置上面定义的参数
    if (err != ESP_OK)
    {
        ESP_LOGE(TAG, "Camera init failed with error 0x%x", err);
        return;
    }

    sensor_t *s = esp_camera_sensor_get(); // 获取摄像头型号

    if (s->id.PID == GC0308_PID)
    {
        s->set_hmirror(s, 1); // 这里控制摄像头镜像 写1镜像 写0不镜像
    }
}
